package com.inspur.edp.lcm.metadata.common;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmFileException;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmMetadataException;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mockStatic;

class ServiceUtilsTest {
    private static String moduleDirName = "metadata-service-common";

    private static File resourceDir = new File("src/test/resources");

    private static File file = new File("src/test/resources/metadata-deploy.jar");

    private static File txtFile = new File("src/test/resources/test.txt");
    private static File zipFile2 = new File("src/test/resources/test2.zip");

    @BeforeAll
    public static void before() throws IOException {
        if (!resourceDir.getCanonicalPath().contains(moduleDirName)) {
            resourceDir = Paths.get(moduleDirName, resourceDir.getPath()).toFile();
            file = Paths.get(moduleDirName, file.getPath()).toFile();
            txtFile = Paths.get(moduleDirName, txtFile.getPath()).toFile();
            zipFile2 = Paths.get(moduleDirName, zipFile2.getPath()).toFile();
        }
        if (!resourceDir.exists()) {
            resourceDir.mkdirs();
        }
    }

    @AfterAll
    public static void after() {
        if (file.exists()) {
            file.delete();
        }
        if (txtFile.exists()) {
            txtFile.delete();
        }
        if (zipFile2.exists()) {
            zipFile2.delete();
        }
    }

    @Test
    void getProjectDeployJar() {
        assertEquals("lcm-project-deploy-tool.jar", ServiceUtils.getProjectDeployJar());
    }

    @Test
    void getMetadataDeployJar() {
        assertEquals("metadata-deploy.jar", ServiceUtils.getMetadataDeployJar());
    }

    @Test
    void getManifestFileName() {
        assertEquals("manifest.json", ServiceUtils.getManifestFileName());
    }

    @Test
    void getMetadataPackageExtension() {
        assertEquals(".mdpkg", ServiceUtils.getMetadataPackageExtension());
    }

    @Test
    void getMapper() {
        ObjectMapper mapper = ServiceUtils.getMapper();
        assertTrue(mapper.isEnabled(SerializationFeature.INDENT_OUTPUT));
    }

    @Test
    void isDeployTool() throws IOException {
        if (!file.exists()) {
            file.createNewFile();
        }

        MockedStatic<CafEnvironment> cafEnvironmentMockedStatic = mockStatic(CafEnvironment.class);
        cafEnvironmentMockedStatic.when(CafEnvironment::getStartupPath).thenReturn(resourceDir.getPath());
        assertTrue(ServiceUtils.isDeployTool());
        file.delete();
        cafEnvironmentMockedStatic.close();
    }

    @Test
    void getStartupPath() {
        MockedStatic<CafEnvironment> cafEnvironmentMockedStatic = mockStatic(CafEnvironment.class);
        cafEnvironmentMockedStatic.when(CafEnvironment::getStartupPath).thenReturn("a");
        assertEquals("a", ServiceUtils.getStartupPath());
        cafEnvironmentMockedStatic.close();
    }

    @Test
    void getBasePath() {
        MockedStatic<ServiceUtils> serviceUtilsMockedStatic = mockStatic(ServiceUtils.class);
        serviceUtilsMockedStatic.when(ServiceUtils::isDeployTool).thenReturn(false);
        serviceUtilsMockedStatic.when(ServiceUtils::getBasePath).thenCallRealMethod();
        MockedStatic<CafEnvironment> cafEnvironmentMockedStatic = mockStatic(CafEnvironment.class);
        cafEnvironmentMockedStatic.when(CafEnvironment::getBasePath).thenReturn("a");
        assertEquals("a", ServiceUtils.getBasePath());

        serviceUtilsMockedStatic.when(ServiceUtils::isDeployTool).thenReturn(true);
        cafEnvironmentMockedStatic.when(CafEnvironment::getStartupPath).thenReturn("/a/a/a/a/a");
        assertEquals("/a", ServiceUtils.getBasePath());

        cafEnvironmentMockedStatic.close();
        serviceUtilsMockedStatic.close();
    }

    @Test
    void getServerRTPath() {
        MockedStatic<CafEnvironment> cafEnvironmentMockedStatic = mockStatic(CafEnvironment.class);
        cafEnvironmentMockedStatic.when(CafEnvironment::getServerRTPath).thenReturn("a");
        assertEquals("a", ServiceUtils.getServerRTPath());
        cafEnvironmentMockedStatic.close();
    }

    @Test
    void handlePath() {
        assertEquals("a/b", ServiceUtils.handlePath("a\\b"));
    }

    @Test
    void getAbsoluteConfigFilePath() throws IOException {
        if (!file.exists()) {
            file.createNewFile();
        }
        MockedStatic<CafEnvironment> cafEnvironmentMockedStatic = mockStatic(CafEnvironment.class);
        cafEnvironmentMockedStatic.when(CafEnvironment::getStartupPath).thenReturn("a");
        cafEnvironmentMockedStatic.when(CafEnvironment::getServerRTPath).thenReturn(resourceDir.getPath());
        assertTrue(new File(ServiceUtils.getAbsoluteConfigFilePath(file.getName())).exists());
        file.delete();
        cafEnvironmentMockedStatic.close();
    }

    @Test
    void readCompressedFile() throws IOException {
        if (!txtFile.exists()) {
            txtFile.createNewFile();
        }
        new FileServiceImp().fileUpdate(txtFile.getPath(), "a");
        compressFile(txtFile.getPath(), zipFile2.getPath());
        txtFile.delete();

        Map<String, String> stringStringMap = ServiceUtils.readCompressedFile(zipFile2);
        zipFile2.delete();
        assertEquals("a", stringStringMap.get("test.txt"));
    }

    @Test
    void checkExist() {
        assertThrows(LcmFileException.class, () -> ServiceUtils.checkExist(new File("a"), "a"));
    }

    @Test
    void checkEmpty() {
        assertThrows(LcmMetadataException.class, () -> ServiceUtils.checkEmpty("", "msg"));
    }

    @Test
    void checkNPE() {
        assertThrows(LcmMetadataException.class, () -> ServiceUtils.checkNPE(null, "msg"));
    }

    private void compressFile(String sourceFilePath, String zipFilePath) {
        try {
            // 创建压缩输出流
            FileOutputStream fos = new FileOutputStream(zipFilePath);
            ZipOutputStream zipOut = new ZipOutputStream(fos);

            // 创建输入流来读取源文件
            File fileToZip = new File(sourceFilePath);
            FileInputStream fis = new FileInputStream(fileToZip);

            // 创建压缩文件的条目（entry）
            ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
            zipOut.putNextEntry(zipEntry);

            // 将源文件的内容写入压缩输出流
            byte[] bytes = new byte[1024];
            int length;
            while ((length = fis.read(bytes)) >= 0) {
                zipOut.write(bytes, 0, length);
            }

            // 关闭流
            fis.close();
            zipOut.close();
            fos.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}